import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:ideology/features/models/editor_tab.dart';
import 'package:ideology/features/models/sample_file.dart';
import 'package:ideology/features/screens/widgets/editor_menu_bar/dialogs/new_project_dialog/new_project_dialog.dart';
import 'package:ideology/shared/services/file_service.dart';
import 'package:ideology/shared/widgets/file_explorer/file_explorer_controller.dart';
import 'package:ideology/shared/widgets/file_explorer/file_node.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'explorer_state_manager.dart';

typedef DirectoryToLazyNode = FileNode Function(Directory dir);

/// 项目管理器
///
/// 负责：
/// - 打开/关闭/新建项目
/// - 资源管理器状态的初始化、刷新与持久化
/// - 管理标签页、自动保存、监听清理等
/// - 与外部服务（[FileService]、[ExplorerStateManager]、[FileExplorerController] 等）交互
class ProjectManager {
  ProjectManager({
    required FileService fileService,
    required DirectoryToLazyNode directoryToLazyNode,
    required FileExplorerController explorerController,
    required ValueNotifier<List<FileNode>> roots,
    required void Function(String?) setProjectRootPath,
    required String? Function() getProjectRootPath,
    required void Function(String dirPath) startDirectoryWatch,
    required void Function(String dirPath) startDirectoryPolling,
    required void Function() stopAllWatchAndPoll,
    required ExplorerStateManager explorerState,
    required VoidCallback onNotify,
    required ValueNotifier<List> tabs,
    required ValueNotifier<int> activeTabIndex,
    required ValueNotifier status,
    required VoidCallback clearAutoSavesAndWatchersForAllTabs,
  })  : _fileService = fileService,
        _directoryToLazyNode = directoryToLazyNode,
        _explorerController = explorerController,
        _roots = roots,
        _setProjectRootPath = setProjectRootPath,
        _getProjectRootPath = getProjectRootPath,
        _startDirectoryWatch = startDirectoryWatch,
        _startDirectoryPolling = startDirectoryPolling,
        _stopAllWatchAndPoll = stopAllWatchAndPoll,
        _explorerState = explorerState,
        _onNotify = onNotify,
        _tabs = tabs,
        _activeTabIndex = activeTabIndex,
        _clearAutoSavesAndWatchersForAllTabs =
            clearAutoSavesAndWatchersForAllTabs;

  final FileService _fileService;
  final DirectoryToLazyNode _directoryToLazyNode;
  final FileExplorerController _explorerController;
  final ValueNotifier<List<FileNode>> _roots;
  final void Function(String?) _setProjectRootPath;
  final String? Function() _getProjectRootPath;
  final void Function(String dirPath) _startDirectoryWatch;
  final void Function(String dirPath) _startDirectoryPolling;
  final void Function() _stopAllWatchAndPoll;
  final ExplorerStateManager _explorerState;
  final VoidCallback _onNotify;

  final ValueNotifier<List> _tabs;
  final ValueNotifier<int> _activeTabIndex;
  final VoidCallback _clearAutoSavesAndWatchersForAllTabs;

  // ——————————————————————————— Public API ——————————————————————————— //

  /// 加载指定目录 [dirPath] 作为项目
  ///
  /// - 设置当前项目路径
  /// - 启动目录监听与轮询
  /// - 初始化资源管理器根节点
  /// - 尝试恢复资源管理器的展开/选中/滚动状态
  /// - 通知 UI 更新
  Future<void> loadProjectAt(String dirPath) async {
    _setProjectRootPath(dirPath);

    _startDirectoryWatch(dirPath);
    _startDirectoryPolling(dirPath);

    final Directory dir = _fileService.directory(dirPath);
    final FileNode rootNode = _directoryToLazyNode(dir);

    // 通过“新列表”赋值触发 UI（对象身份变化）
    _roots.value = [rootNode];

    // 选中/展开根节点，随后让持久化覆盖（如有）
    _explorerController.selectedPath.value = rootNode.name;
    _explorerController.expanded.value = {rootNode.name};

    // 先尝试恢复资源管理器的展开/选中/滚动等状态
    await _explorerState.restoreForProject(dirPath);

    // 通知其它 UI
    _onNotify();
  }

  /// 刷新资源管理器
  ///
  /// 会保留当前展开与选中状态，并重建根节点
  void refreshExplorer() {
    final path = _getProjectRootPath();
    if (path == null) return;

    final expanded = {..._explorerController.expanded.value};
    final selected = _explorerController.selectedPath.value;

    final Directory dir = _fileService.directory(path);
    _roots.value = [_directoryToLazyNode(dir)];
    _explorerController.expanded.value = expanded;
    _explorerController.selectedPath.value = selected;

    _onNotify();
  }

  /// 释放所有资源并保存状态
  Future<void> disposeAll() async {
    final root = _getProjectRootPath();
    if (root != null) {
      await _explorerState.saveForProject(root);
    }

    // 清空各类 watcher/poller
    _stopAllWatchAndPoll();

    // 释放 Tab
    for (final t in List.of(_tabs.value)) {
      _clearAutoSavesAndWatchersForAllTabs();
      t.dispose();
    }
  }

  /// 关闭当前项目
  ///
  /// - 停止监听、清理资源
  /// - 释放所有标签页并清空 UI 状态
  /// - 清理持久化记录（包括上次路径与资源管理器状态）
  /// - 通知 UI 回到初始页
  Future<void> closeCurrentProject() async {
    final root = _getProjectRootPath();

    // 1) 停止监听、清理资源
    _stopAllWatchAndPoll();
    _clearAutoSavesAndWatchersForAllTabs();

    // 2) 释放所有标签页（用“新列表”以触发监听）
    for (final tab in List<EditorTab>.from(_tabs.value)) {
      tab.dispose();
    }
    _tabs.value = <EditorTab>[];
    _activeTabIndex.value = -1;

    // 3) 清空 Explorer 视图（新空列表触发对象身份变化 -> 初始页）
    _roots.value = <FileNode>[];
    _explorerController.selectedPath.value = '';
    _explorerController.expanded.value = <String>{};

    // 4) 清理“上次项目路径”与该项目的 Explorer 持久化状态
    await _clearProjectPathFromPreferences();
    if (root != null) {
      await _explorerState.clearForProject(root);
    }

    // 5) 置空当前项目路径 & 通知 UI
    _setProjectRootPath(null);
    _fileService.closeProject();
    _onNotify();
  }

  /// 清理 SharedPreferences 中的项目路径记录
  Future<void> _clearProjectPathFromPreferences() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove('lastProjectPath'); // 移除持久化的项目路径
  }

  /// 使用对话框数据新建项目
  ///
  /// - 若未指定路径，则通过文件选择器选择目录
  /// - 自动避免命名冲突（`xxx`, `xxx_1`, …）
  /// - 可选生成示例文件（`project.cloud`）
  /// - 创建完成后自动加载该项目
  Future<void> createNewProjectWith(NewProjectData data) async {
    String? baseDir = data.location;
    if (baseDir == null || baseDir.trim().isEmpty) {
      baseDir = await _fileService.pickDirectory();
      if (baseDir == null) return;
    }

    String rawName = data.name.trim().isEmpty ? 'untitled' : data.name.trim();
    String candidate(String name, int i) => i == 0 ? name : '${name}_$i';

    int i = 0;
    late String dirPath;
    while (true) {
      final tryName = candidate(rawName, i);
      dirPath = _fileService.join(baseDir, tryName);
      final exists = await _fileService.dirExists(dirPath);
      if (!exists) break;
      i++;
      if (i > 200) break;
    }

    final dir = Directory(dirPath);
    await dir.create(recursive: true);
    try {
      if (data.withSample) {
        final samples = SampleFile.cloudFilesForName(
          rawName,
          group: data.group,
        );
        for (final f in samples) {
          final file = File(_fileService.join(dirPath, f.relativePath));
          await file.create(recursive: true);
          await file.writeAsString(f.contents);
        }
      }
    } catch (_) {
      // Web 等环境不支持 dart:io，忽略写入失败
    }

    await loadProjectAt(dirPath);
  }
}
